﻿using System;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using Newtonsoft_X.Json;
using Net.Helper;
using Net.Share;
using Net.System;
using Debug = Net.Event.NDebug;

namespace Net.Server
{
    public class WebServerNew<Player, Scene> : ServerBase<Player, Scene> where Player : WebPlayerNew, new() where Scene : SceneBase<Player>, new()
    {
        /// <summary>
        /// websocket连接策略, 有wss和ws
        /// </summary>
        public string Scheme { get; set; } = "ws";
        /// <summary>
        /// 证书
        /// </summary>
        public X509Certificate2 Certificate { get; set; }
        /// <summary>
        /// Ssl类型
        /// </summary>
        public SslProtocols SslProtocols { get; set; }
        private RemoteCertificateValidationCallback _clientCertValidationCallback;
        public RemoteCertificateValidationCallback ClientCertificateValidationCallback
        {
            get => _clientCertValidationCallback ??= DefaultValidateClientCertificate;
            set => _clientCertValidationCallback = value;
        }
        public bool ClientCertificateRequired { get; private set; }
        public bool CheckCertificateRevocation { get; private set; }

        private bool DefaultValidateClientCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => true;

        protected override void StartProcessAccept()
        {
            var thread = new Thread(ProcessAcceptConnect)
            {
                IsBackground = true,
                Name = "ProcessAcceptConnect"
            };
            thread.Start();
            ServerThreads.Add("ProcessAcceptConnect", thread);
        }

        protected override void CreateServerSocket(int port)
        {
            try
            {
                var address = new IPEndPoint(IPAddress.Any, port);
                Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
                {
                    SendBufferSize = Config.SendBufferSize,
                    ReceiveBufferSize = Config.ReceiveBufferSize,
                    NoDelay = true
                };
                Certificate ??= CertificateHelper.GetDefaultCertificate();
                Server.Bind(address);
                Server.Listen(Config.OnlineLimit + Config.LineUp);
            }
            catch (Exception ex)
            {
                Debug.LogError("监听异常:" + ex);
            }
        }

        private void ProcessAcceptConnect()
        {
            var acceptList = new FastList<WebSocketSession>();
            WebSocketSession session;
            while (IsRunServer)
            {
                try
                {
                    if (Server.Poll(performance, SelectMode.SelectRead))
                    {
                        var socket = Server.Accept();
                        socket.ReceiveTimeout = (int)Config.ReconnectionTimeout;
                        session = new WebSocketSession(socket)
                        {
                            performance = performance
                        };
                        var stream = new NetworkStream(socket);
                        if (Scheme == "wss")
                        {
                            var sslStream = new SslStream(stream, false, ClientCertificateValidationCallback);
                            sslStream.AuthenticateAsServer(Certificate, ClientCertificateRequired, SslProtocols, CheckCertificateRevocation);
                            session.stream = sslStream;
                        }
                        else session.stream = stream;
                        acceptList.Add(session);
                    }
                    else Thread.Sleep(1);
                    CheckAcceptList(acceptList);
                }
                catch (Exception ex)
                {
                    Debug.LogError($"接受异常:{ex}");
                }
            }
        }

        private void CheckAcceptList(FastList<WebSocketSession> acceptList)
        {
            WebSocketSession session;
            for (int i = 0; i < acceptList.Count; i++)
            {
                session = acceptList[i];
                if (!session.Connected)
                {
                    session.Close();
                    acceptList.RemoveAt(i);
                    continue;
                }
                if (!session.isHandshake)
                {
                    session.PerformHandshake();
                    continue;
                }
                var code = session.Receive(session, (object state, Opcode opcode, ref ISegment segment) =>
                {
                    CheckReconnect(session.socket, segment, session);
                    acceptList.RemoveAt(i);
                });
                if (code == -1)
                {
                    session.Close();
                    acceptList.RemoveAt(i);
                }
            }
        }

        protected override void AcceptHander(Player client, params object[] args)
        {
            var session = args[0] as WebSocketSession;
            client.Session = session;
            client.Set();
        }
    }

    public class WebServerNew : WebServerNew<WebPlayerNew, SceneBase<WebPlayerNew>>
    {
    }
}
